﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.SharePoint.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ZhukBlogLinqExamples.Model;
using ZhukBlogLinqExamples.Repositories;

namespace ZhukBlogLinqExamples.UnitTests
{
    [TestClass]
    public class RepositoryUnitTests
    {
        public TestContext TestContext { get; set; }

        #region Additional test attributes

        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //

        #endregion

        [TestMethod]
        public void CreateEmployee()
        {
            var entry = new Employee
                            {
                                Title = GetRandomEmployeeTitle(),
                                CellPhone = "+79057746571"
                            };
            var repository = new EmployeeRepository(SiteUrl, false);
            repository.SaveEntity(entry);
            if (!entry.Id.HasValue)
            {
                Assert.Fail("Entity doesn't have Id as creating.");
            }
        }

        [TestMethod]
        public void DeleteEmployee()
        {
            var repository = new EmployeeRepository(SiteUrl, false);
            var entry = repository.GetEntityCollection().FirstOrDefault();
            if (entry != null)
            {
                repository.DeleteEntity(entry);
                if (repository.GetEntity(entry.Id.Value) != null)
                {
                    Assert.Fail("Entity exists after deleting.");
                }
            }
        }

        [TestMethod]
        public void UpdateEmployee()
        {
            var repository = new EmployeeRepository(SiteUrl, false);
            var entry = repository.GetEntityCollection().FirstOrDefault();
            if (entry != null)
            {
                entry.Title = GetRandomEmployeeTitle();
                repository.SaveEntity(entry);
                if (entry.EntityState != EntityState.Unchanged)
                {
                    Assert.Fail("EntityState doesn't equal EntityState.Unchanged.");
                }
            }
        }

        [TestMethod]
        public void EmployeeExistsInContext()
        {
            var repository = new EmployeeRepository(SiteUrl, false);
            var entry = new Employee
                            {
                                Title = GetRandomEmployeeTitle(),
                                CellPhone = "+79057746571"
                            };
            var flag = repository.EntityExistsInContext(entry);
            if (flag)
            {
                Assert.Fail("New entity is attached in context.");
            }
            repository.SaveEntity(entry);
            flag = repository.EntityExistsInContext(entry);
            if (!flag)
            {
                Assert.Fail("Saved entity isn't attached in context.");
            }
        }

        [TestMethod]
        public void RetrievingListMetaData()
        {
            var repository = new EmployeeRepository(SiteUrl, false);
            var data = repository.MetaData;
            if (data.ContentTypes.Count == 0)
            {
                Assert.Fail("There is no any ContentType in list.");
            }
            if (data.Fields.Count == 0)
            {
                Assert.Fail("There is no any Fields in list.");
            }
            if (data.BaseType != EntityListBaseType.GenericList)
            {
                Assert.Fail("Employee list is not GenericList");
            }
        }

        [TestMethod]
        public void GetEmployeeVersions()
        {
            var repository = new EmployeeRepository(SiteUrl, false);
            var query = repository.GetEntityCollection(emp => emp.Version > 1);
            var items = query.ToList();
            foreach (var employee in items)
            {
                var versions = repository.GetVersions(employee);
                if (versions.Count() == 0)
                {
                    Assert.Fail("There is no version of employee");
                }
            }
        }

        [TestMethod]
        public void DeleteEmployeeVersions()
        {
            var repository = new EmployeeRepository(SiteUrl, false);
            var query = repository.GetEntityCollection(emp => emp.Version > 1);
            var items = query.ToList();
            foreach (var employee in items)
            {
                var versions = repository.GetVersions(employee);
                if (versions.Count() == 0)
                {
                    Assert.Fail("There is no version of employee");
                }
            }
        }

        [TestMethod]
        public void UpdateEmployeeWithDeletionVersion()
        {
            var repository = new EmployeeRepository(SiteUrl, false);
            var query = repository.GetEntityCollection(emp => emp.IsCurrentVersion == true);
            var employee = query.FirstOrDefault();
            if (employee == null)
                Assert.Fail("There is no any employee entity in list");
            employee.Title = GetRandomEmployeeTitle();
            repository.SaveEntity(employee);
            var previosVersion = repository
                .GetVersions(employee)
                .OrderByDescending(x => x.Version)
                .FirstOrDefault();
            if (previosVersion == null)
                Assert.Fail("Previous version of entity is empty");
            repository.DeleteEntity(previosVersion);
        }

        [TestMethod]
        public void CrossSiteCollectionContext()
        {
            var repository1 = new EmployeeRepository("http://mscpc11/linq");
            var repository2 = new EmployeeRepository("http://mscpc11/sites/asc");
        }

        private static string GetRandomEmployeeTitle()
        {
            var rnd = new Random(Environment.TickCount);
            var name = EmployeeNames[rnd.Next(0, EmployeeNames.Length - 1)];
            var surname = EmployeeSurnames[rnd.Next(0, EmployeeSurnames.Length - 1)];
            return string.Format("{0} {1}", name, surname);
        }

        [TestMethod]
        public void ContentIterator()
        {
            

            var repository = new EmployeeRepository(SiteUrl, true, false);
            Expression<Func<Employee, bool>> filter = emp => emp.SexValue == "Male";
            var iterator = new SPLinqContentIterator<Employee>(
                                repository, // Репозиторий
                                filter,  // Предикат для фильтрации
                                string.Empty, // Корневая папка
                                true, // Просматривать дочерние папки
                                ProcessEmployee, // Обработчик элемента
                                HandleErrorEmployee); // Обработчик исключений
            iterator.Begin();
        }

        public void ProcessEmployee(Employee employee, out bool cancelled)
        {
            employee.Title = GetRandomEmployeeTitle();
            cancelled = true;
        }

        public void HandleErrorEmployee(Employee employee, Exception exception, out bool cancelled)
        {
            cancelled = false;
        }

        private const string SiteUrl = "http://mscpc11/sites/asc/";// "http://mscpc11/linq";

        private static readonly string[] EmployeeNames = new[]
                                                              {
                                                                  "Michael",
                                                                  "David",
                                                                  "Joseph",
                                                                  "Paul",
                                                                  "Doanld",
                                                                  "Brian",
                                                                  "Ronald",
                                                                  "Jerry",
                                                                  "Jack",
                                                                  "Roy",
                                                                  "Vitaly",
                                                                  "Anton",
                                                                  "Vladimir",
                                                                  "Bill",
                                                                  "Alex",
                                                                  "Peter",
                                                                  "Martin"
                                                              };

        private static readonly string[] EmployeeSurnames = new[]
                                                                 {
                                                                     "Smith",
                                                                     "Jones",
                                                                     "Miller",
                                                                     "Morris",
                                                                     "Bell",
                                                                     "Cook",
                                                                     "James",
                                                                     "Kelly",
                                                                     "Wood",
                                                                     "Flores",
                                                                     "Diaz",
                                                                     "Fisher",
                                                                     "McDonald",
                                                                     "Zhukov",
                                                                  "Sterff",
                                                                  "Robinson",
                                                                  "Sadomov"
                                                                 };
    }
}
